package system.communication;

import java.io.BufferedReader;
import java.io.IOException;
import system.ui.Gui;

/**
 * This Listener reads single messages from the socket's output buffer and
 * sends out the messages to their respective lists in the Monitor for its
 * Thread's run method.
 * 
 * @author Elliot Cash
 * @version Cycle 1 - complete
 */
public class MessageListener extends Thread
{
    public static boolean waiting;
    public BufferedReader br;
    private boolean stop = false;
    private Message currentMessage;
    
    /**
     * Constructor for Objects of class MessageListener.  Accepts a 
     * BufferedReader which parses text from the train system.
     * 
     * @param br    a BufferedReader to the train system
     */
    public MessageListener(BufferedReader br)
    {
        this.br = br;
        //check readiness of the Reader
        try
        {
            if(br.ready())
            {
                while(br.ready())
                {
                    System.out.println("Cleared from br: " + br.read());
                }
            }
        }
        catch(IOException ex)
        {
            System.err.println(ex.getMessage());
        }
    }

    /**
     * The run method for the threaded MessageListener.  The Listener will
     * attempt to read lines from the BufferedReader while it is running,
     * classify the lines as Messages, and divert them to the correct object.
     * 
     */
    @Override
    public void run()
    {
        try
        {
            while(!stop) //while the thread hasn't been ended
            {
                //read the incoming line and trim it for any line breaks
                String line = readLine(br).trim();
                if (!line.equals("")) //if the line contains a message
                {
                    System.out.println(line);
                    currentMessage = new Message(line); //create a Message object
                    //this will allocate the parts of the String to Message type, ID, etc.
                    //now we can get the type of the Message:
                    switch(currentMessage.getType())
                    {
                        //all Message types are sent to the Monitor
                        case BLOCK:
                            ConcreteMonitor.blockMessages.addFirst(currentMessage);
                            break;
                        case SWITCH:
                            ConcreteMonitor.switchMessages.addFirst(currentMessage);
                            //Switch Messages are also sent to the Gui to be displayed to the user
                            Gui.getInstance().postSwitchMessage(currentMessage);
                            break;
                        case HANDCONTROL:
                            ConcreteMonitor.handControlMessages.addFirst(currentMessage);
                            //Hand Control Messages are sent to a special class for processing
                            HandControlMessageNotifier checkHandControlMessages = new HandControlMessageNotifier();
                            checkHandControlMessages.start();
                            break;
                        case SENSOR:
                            ConcreteMonitor.sensorMessages.addFirst(currentMessage);
                            //Sensor Messages are also sent to the Gui to be displayed to the user
                            Gui.getInstance().postSensorMessage(currentMessage);
                            //Sensor Messages are also sent to a Notifier to notify the Train
                            SensorNotifier checkTrippedSensors = new SensorNotifier();
                            checkTrippedSensors.start();
                            break;
                        case LED:
                            ConcreteMonitor.ledMessages.addFirst(currentMessage);
                            break;
                        default:
                            ConcreteMonitor.otherMessages.addFirst(currentMessage);
                    }
                    /*if(ConcreteMonitor.waiting)
                    {
                        ConcreteMonitor.getInstance().notifyForResponse();
                    }*/                
                    Thread.sleep(1);
                    ConcreteMonitor.waiting = false; //activate the Monitor
                }
            }
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    }

    /**
     * Stops the action of the thread; prevents it from continuing to read
     * the BufferedReader.
     */
    public void end()
    {
       try
       {
           br.close();
       }
       catch(IOException ioe)
       {
           System.out.println("ending " + ioe);
       }
       stop = true; //this will stop the reading loop
    }

    /**
     * Reads a line from the BufferedReader.
     * 
     * @param br    a BufferedReader containing information from the 
     * train system
     * @return      a processed String
     * @throws      IOException
     */
    private String readLine(BufferedReader br) throws IOException
    {
        String strtemp = "";
        char x;
        boolean breaker = false;
        while(br.ready() && stop==false)
        {
            //pass characters into the String
            x = (char)br.read();
            strtemp += x;
            if(x == '}') //signals the end of the message
            {
                breaker = true;
                break;
            }
        }
        return strtemp;
    }
}